/* License Notice:
**
** This program is free software: you can redistribute it and/or modify
**    it under the terms of the GNU General Public License as published by
**    the Free Software Foundation, either version 3 of the License, or
**    (at your option) any later version.
** This program is distributed in the hope that it will be useful,
**   but WITHOUT ANY WARRANTY; without even the implied warranty of
**   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
**   GNU General Public License for more details.
** You should have received a copy of the GNU General Public License
**   along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

/**
 * @file effect_sources.cpp
 * @author TooOld2Rock'nRoll
 * @see effect_sources.hpp
 *
 * @todo Maybe including audio.hpp is a bad idea, get the device info from Mixer instead? Doing this for every file would be costly.
 * @bug Can we load Mix_Chunks without opening the audio device first? Calculating the chunk duration depends on it today, can we place this calculation on the play procedure????<br>
 *      What if we close and open a different device? All the chunks would have to be reloaded!
 */
/*---- Includes ----*/
#include "audio/audio.hpp"
#include "audio/effect_sources.hpp"

#include "toolbox/debug.h"


/*---- Methods Implementation ----*/
/**
 * @brief Loads a audio file as a sound effect source.
 *
 * @param file - the audio file path.
 *
 * @throws std::invalid_argument - in case the file path is null.
 * @throws std::runtime_error - in case loading the file is not possible or Audio Device is close.
 */
DecodedFileSource::DecodedFileSource (const char *file)
{
    const Audio::audio_device_st *audio_info = Audio::instance().getAudioDeviceInfo ();
    Uint32 samples = 0;

    _debug (TRACE, "::%s (file='%s')", __FUNCTION__, file);

    if (!audio_info)
        throw std::runtime_error (fmt::format ("{0}:{1} - Can't load an Effect without the audio device's info! (No Audio Device open, probably)", __LINE__, __FILE__));
    if (!file)
        throw std::invalid_argument (fmt::format ("{0}:{1} - An audio file is necessary, file path is null!", __LINE__, __FILE__));

    this->p_native_audio_data = Mix_LoadWAV (file);
    if (!this->p_native_audio_data)
        throw std::runtime_error (fmt::format ("{0}:{1} - The '{2}' file can't be loaded, error:\r\n{3}", __LINE__, __FILE__, file, Mix_GetError()));

    //compute the chunk duration in seconds
    //thanks to Carlos Faruolo's (a.k.a. hydren) for the procedure.
    //https://gist.github.com/hydren/68ae34d596fca69bd196c6fed4210c72#file-custom_mix_pitch-c-L6
    if (audio_info)
    {
        samples = this->p_native_audio_data->alen / ((audio_info->t_format & 0xFF) >> 3); //won't work on Mac? Does it matter? Divide by 8 instead?
        this->d_length = (samples / (float)audio_info->u_channels) / audio_info->u_frequency;
    }//end if
    else
        _debug (ERROR, "Trying to load Mix_Chunk with the Audio Device closed, can't calculate its duration!");
}//end constructor

/**
 * @brief Sets the specific Effect playback volume.
 *
 * It will still be mixed against the major SoundEffects volume and the master volume that regulates all sounds.
 *
 * @param volume - from 0 to 100.
 */
void DecodedFileSource::setVol (unsigned short volume)
{
    _debug (TRACE, "::%s (vol=%u)", __FUNCTION__, volume);

    this->us_volume = (volume > 100 ? 100 : volume);
    Mix_VolumeChunk (this->p_native_audio_data, MIX_MAX_VOLUME * (this->us_volume / 100.f));
}//End setVol ()

